#include <iostream>
#include <mutex>
#include <unordered_map>
#include <vector>
#include <functional>
#include <typeindex> // 用于获取类型信息
#include <future>    // 用于保存异步任务结果
#include <chrono>
#include <memory>

using namespace std;

class EventBus {
private:
	unordered_map<type_index, vector<function<void(const void *)>>> subscribers;
	mutex                                                           mtx;

public:
	// 订阅事件
	template<typename T>
	size_t Subscribe(function<void(const T &)> handler) {
		lock_guard<mutex> lock(mtx);
		type_index        type = typeid(T);

		auto wrapper = [handler](const void *event) { handler(*static_cast<const T *>(event)); };
		subscribers[type].push_back(wrapper);
		return subscribers[type].size() - 1;
	}

	// 取消订阅
	template<typename T>
	bool Unsubscribe(size_t token) {
		lock_guard<mutex> lock(mtx);
		type_index        type = typeid(T);

		if (!subscribers.count(type) || token >= subscribers[type].size()) {
			return false;
		}

		subscribers[type][token] = nullptr;
		return true;
	}

	template<typename T>
	void PublishAsync(const T &event) {
		vector<function<void(const void *)>> activeHandlers;
		{
			lock_guard<mutex> lock(mtx);
			type_index        type = typeid(T);

			if (!subscribers.count(type)) return;

			// 仅收集非空handler
			for (const auto &handler: subscribers[type]) {
				if (handler) { // 过滤已取消订阅的handler
					activeHandlers.push_back(handler);
				}
			}
		}

		// 用shared_ptr保存事件副本，确保异步任务中生命周期有效
		auto                 eventPtr = make_shared<T>(event);
		vector<future<void>> futures; // 保存future对象
		for (const auto &handler: activeHandlers) {
			// 保存future（避免部分编译器优化导致同步执行）
			// 实际场景可存入全局容器管理，此处简化为立即丢弃（多数实现仍异步）
			futures.push_back(async(launch::async, [handler, eventPtr]() {
				handler(eventPtr.get()); // 使用共享指针的地址，避免引用失效
			}));
		}
	}
};

// 定义事件类型（示例）
struct PerformanceEvent {
	int id;
};

void TestParallelExecution() {
	cout << "=== 测试并行执行 ===" << endl;
	EventBus bus;

	// 订阅者1：耗时2秒
	auto token1 = bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) {
		cout << "订阅者1 开始处理事件 " << e.id << endl;
		this_thread::sleep_for(chrono::seconds(2));
		cout << "订阅者1 完成处理事件 " << endl;
	});

	// 订阅者2：无延迟
	auto token2 = bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) { cout << "订阅者2 处理事件 " << e.id << endl; });

	bus.PublishAsync(PerformanceEvent{100});
	getchar(); // 阻塞等待所有任务完成

	// 预期输出：
	// === 测试并行执行 ===
	// 订阅者1 开始处理事件 100
	// 订阅者2 处理事件 100
	// 订阅者1 完成处理事件
}
void TestUnsubscribe() {
	cout << "\n=== 测试取消订阅 ===" << endl;
	EventBus bus;

	auto token1 = bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) { cout << "该订阅者已取消，不应被调用" << endl; });

	// 取消订阅
	bool success = bus.Unsubscribe<PerformanceEvent>(token1);
	cout << "取消订阅结果：" << (success ? "成功" : "失败") << endl;

	bus.PublishAsync(PerformanceEvent{200});
	getchar();
}

// 模块A：订阅事件
namespace ModuleA {
	void Init(EventBus &bus) {
		bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) { cout << "模块A 收到事件 " << e.id << endl; });
	}
} // namespace ModuleA

// 模块B：订阅同一事件
namespace ModuleB {
	void Init(EventBus &bus) {
		bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) { cout << "模块B 收到事件 " << e.id << endl; });
	}
} // namespace ModuleB

void TestMultiModule() {
	cout << "\n=== 测试多模块共享总线 ===" << endl;
	EventBus bus; // 单例总线，供多模块共享

	ModuleA::Init(bus);
	ModuleB::Init(bus);

	bus.PublishAsync(PerformanceEvent{300});
	this_thread::sleep_for(chrono::seconds(1));
	// 预期：模块A和模块B同时输出收到事件300
}

// 新增事件类型
struct LogEvent {
	string message;
};

void TestMultiEventType() {
	cout << "\n=== 测试多事件类型 ===" << endl;
	EventBus bus;

	// 订阅PerformanceEvent
	bus.Subscribe<PerformanceEvent>([](const PerformanceEvent &e) { cout << "处理性能事件 " << e.id << endl; });

	// 订阅LogEvent()
	bus.Subscribe<LogEvent>([](const LogEvent &e) { cout << "处理日志事件：" << e.message << endl; });

	bus.PublishAsync(PerformanceEvent{400});
	bus.PublishAsync(LogEvent{"系统启动完成"});
	this_thread::sleep_for(chrono::seconds(1));
	// 预期：两类事件的订阅者分别被触发
}

// 编译： g++ -std=c++11 -pthread event_bus_task.cpp -o event_bus_task.exe
int main() {
	TestParallelExecution();
	TestUnsubscribe();
	TestMultiModule();
	TestMultiEventType();
	return 0;
}
